﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using AutoMapper;


namespace MongoManager
{

    public class MongoManager<T> where T : IMongoEntity
    {
        private string _databaseName;
        private string _collectionName;
        private Mongo _mongo = null;
        private Database _database = null;
        private IMongoCollection _collection = null;

        public MongoManager(string databaseName, string collectionName) : this(databaseName, collectionName, Connection.DEFAULTHOST, Connection.DEFAULTPORT, Connection.DEFAULTHOST, Connection.DEFAULTPORT, false) { }
        public MongoManager(string databaseName, string collectionName, string host, int port) : this(databaseName, collectionName, host, port, Connection.DEFAULTHOST, Connection.DEFAULTPORT, false) { }
        public MongoManager(string databaseName, string collectionName, string leftHost, int leftPort, string rightHost, int rightPort) : this(databaseName, collectionName, leftHost, leftPort, rightHost, rightPort, false) { }
        public MongoManager(string databaseName, string collectionName, string leftHost, int leftPort, string rightHost, int rightPort, bool slaveOk)
        {
            _databaseName = databaseName;
            _collectionName = collectionName;

            if (rightHost != Connection.DEFAULTHOST && rightPort != Connection.DEFAULTPORT)
                _mongo = new MongoDB.Driver.Mongo(leftHost, leftPort, rightHost, rightPort, slaveOk);
            else
                _mongo = new MongoDB.Driver.Mongo(leftHost, leftPort);

            _mongo.Connect();

        }

        public Database Database
        {
            get
            {
                if (_database == null) _database = _mongo.getDB(_databaseName);

                return _database;
            }
        }

        public IMongoCollection Collection
        {
            get
            {
                if (_collection == null) _collection = Database.GetCollection(_collectionName);

                return Database.GetCollection(_collectionName);
            }
        }

        public T Load(T item)
        {
            Document query = Mapper.Map<T, Document>(item);
            Document foundDoc = Collection.FindOne(query);


            T foundItem = Mapper.Map<Document, T>(foundDoc);

            return foundItem;
        }

        public void Delete(T item)
        {
            Document query = Mapper.Map<T, Document>(item);

            Collection.Delete(query);
        }

        public void Save(ref T item)
        {
            Document query = Mapper.Map<T, Document>(item);

            if (string.IsNullOrEmpty(item.ID))
            {
                Collection.Insert(query);

                List<T> items = Find(item);

                item.ID = items[0].ID;
            }
            else
                Collection.Update(query);
        }

        public List<T> FindAll()
        {
            List<T> items = new List<T>();


            foreach (Document item in Collection.FindAll().Documents)
            {
                T newItem = Mapper.Map<Document, T>(item);
                items.Add(newItem);
            }

            return items;
        }

        public List<T> Find(T userToFind)
        {
            List<T> items = new List<T>();
            Document query = Mapper.Map<T, Document>(userToFind);


            foreach (Document item in Collection.Find(query).Documents)
            {
                T newItem = Mapper.Map<Document, T>(item);
                items.Add(newItem);
            }

            return items;
        }

    }

}
